

#include"RayCaster.h"
#include <assert.h>
#define HISTO_Y 200

RayCaster::RayCaster(int w, int h)
{
	//set status
	m_x = 1.0;
	m_y = 1.0;
	m_z = 1.0;
	m_Width = w;
	m_Height = h;
	stepsize = float(0.003);
	iso_value = float(0.2);
    
	m_rotationY = 0;
	m_rotationX = 0;


}

RayCaster::~RayCaster()
{
}

inline unsigned char lerp(unsigned char a, unsigned char b, double t)
{
	return unsigned char(a*t+b*(1-t));
}

unsigned char texture3D(unsigned char* vol, double indexZf, double indexYf, double indexXf, int sizeZ, int sizeY, int sizeX)
{
	unsigned char value=0;
	//sizeZ--;
	//sizeY--;
	//sizeX--;
	int indexZ = int( indexZf*(sizeZ-1));
	int indexY = int( indexYf*(sizeY-1));
	int indexX = int( indexXf*(sizeX-1));

	double offsetZ = indexZf*(sizeZ-1) - indexZ;
	double offsetY = indexYf*(sizeY-1) - indexY;
	double offsetX = indexXf*(sizeX-1) - indexX;

	//http://en.wikipedia.org/wiki/Trilinear_interpolation
	unsigned char v000, v001,v011, v010, v100, v101,v111, v110;
	unsigned char v00, v01, v11, v10;
	unsigned char v0, v1;
	v000 = vol[sizeX*sizeY*(indexZ+0) + sizeX*(indexY+0) + indexX+0];
	v001 = vol[sizeX*sizeY*(indexZ+0) + sizeX*(indexY+0) + indexX+1];
	v011 = vol[sizeX*sizeY*(indexZ+0) + sizeX*(indexY+1) + indexX+1];
	v010 = vol[sizeX*sizeY*(indexZ+0) + sizeX*(indexY+1) + indexX+0];
	v100 = vol[sizeX*sizeY*(indexZ+1) + sizeX*(indexY+0) + indexX+0];
	v101 = vol[sizeX*sizeY*(indexZ+1) + sizeX*(indexY+0) + indexX+1];
	v111 = vol[sizeX*sizeY*(indexZ+1) + sizeX*(indexY+1) + indexX+1];
	v110 = vol[sizeX*sizeY*(indexZ+1) + sizeX*(indexY+1) + indexX+0];

	v00 = lerp(v000, v100, 1-offsetZ); 
	v01 = lerp(v001, v101, 1-offsetZ);
	v11 = lerp(v011, v111, 1-offsetZ);
	v10 = lerp(v010, v110, 1-offsetZ);

	v0 = lerp(v00, v10, 1-offsetY); 
	v1 = lerp(v01, v11, 1-offsetY);

	value = lerp(v0, v1, 1-offsetX);

	return value;
}

void RayCaster::updateHiresBoundary()
{
	/*//test texture3D, testing works
	unsigned char temp[8]={0,255,0,255,0,255,0,255};
	unsigned char value = texture3D(temp, 0.1,0.2,0.3,2,2,2);
	*/
		for(int j=0; j<YMAX; j++)
			for(int k=0; k<ZMAX; k++)
			{
				int indexZ = k/2, indexY=j/2;
				double indexZf = double(k)/double(ZMAX);
				double indexYf = double(j)/double(YMAX);
				//double offsetZ = indexZf*ZMAX - int(indexZ);
				//double offsetY = indexYf*YMAX - int(indexY);
				////
				//_hiresVol[XMAX*YMAX*k + YMAX*j + XMAX/2-1] = 0;
				//_hiresVol[XMAX*YMAX*k + YMAX*j + XMAX/2-1] = _lowresVol[XMAX/2*YMAX/2*indexZ + YMAX/2*indexY + XMAX/4 ];
				_hiresVol[XMAX*YMAX*k + YMAX*j + XMAX/2-1] = texture3D(_lowresVol, indexZf, indexYf, double(XMAX/2-1)/double(XMAX), ZMAX/2, YMAX/2, XMAX/2);

			}
}

bool RayCaster::LoadLowRes(char *filename)
{
	//loading 128X128X128
	printf("loading low res 3D volume data ... \n");
	FILE *pFile = fopen(filename,"rb");
	if (NULL == pFile) {
		return false;
	}

	//int size = XMAX*YMAX*ZMAX;
	int size = XMAX*YMAX*ZMAX;

	unsigned char *pVolume = new unsigned char[size];
	memset(pVolume,0,size*sizeof(unsigned char));
	
	bool testvolume = false;
	if(testvolume)
	{
		//testVolume(pVolume, XMAX);
	}
	else
	{
		bool ok = (size == fread(pVolume,sizeof(unsigned char), size,pFile));
		fclose(pFile);
	}

	//========================Calculate histogram======================
	for(int i=0; i<256; i++)
	{
		histogram[i] = 0;
	}

	int m = 0;
	for(int i=0; i<size; i++)
	{
		if(pVolume[i]>m)
			m = pVolume[i];
		histogram[pVolume[i]]++;
	}

	double maxvalue = 0;
	//histogram[0] = 0;
	for(int i=0; i<256; i++)
	{
		histogram[i] = log(histogram[i]);

		if(histogram[i]>maxvalue)
		maxvalue = histogram[i];
	}

	

	maxvalue = maxvalue;

	for(int i=0; i<256; i++)
	{
		histogram[i] = histogram[i]/maxvalue*HISTO_Y;
	}
	//=================================================================
	_lowresVol = pVolume;
	glGenTextures(1, &m_lowResVolume);
	glBindTexture(GL_TEXTURE_3D,m_lowResVolume);

	glPixelStorei(GL_PACK_ALIGNMENT, 1);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

	// set the texture parameters
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexImage3D(GL_TEXTURE_3D,0,GL_INTENSITY,XMAX,YMAX,ZMAX,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,pVolume);

}

bool RayCaster::LoadVolume(char *filename)
{
	printf("loading 3D volume data ... \n");
	FILE *pFile = fopen(filename,"rb");
	if (NULL == pFile) {
		return false;
	}

	//int size = XMAX*YMAX*ZMAX;
	int size = XMAX*YMAX*ZMAX;

	unsigned char *pVolume = (unsigned char*)malloc(size*sizeof(unsigned char));
	memset(pVolume,0,size*sizeof(unsigned char));
	
	bool testvolume = false;
	if(testvolume)
	{
		//testVolume(pVolume, XMAX);
	}
	else
	{
		bool ok = (size == fread(pVolume,sizeof(unsigned char), size,pFile));
		fclose(pFile);
	}


	glGenTextures(MAXVOLUMETEXTURE,m_volumeTexture);
	

	glBindTexture(GL_TEXTURE_3D,m_volumeTexture[0]);

	//fuck ah.....
	glPixelStorei(GL_PACK_ALIGNMENT, 1);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	// set the texture parameters
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	//glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	//glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	glTexImage3D(GL_TEXTURE_3D,0,GL_INTENSITY,XMAX,YMAX,ZMAX, 0, GL_LUMINANCE,GL_UNSIGNED_BYTE,pVolume);

	//========================Caculate histogram======================
	for(int i=0; i<256; i++)
	{
		histogram[i] = 0;
	}

	for(int i=0; i<size; i++)
	{
		histogram[pVolume[i]]++;
	}

	double maxvalue = 0;
	//histogram[0] = 0;
	for(int i=0; i<256; i++)
	{
		histogram[i] = log(histogram[i]);

		if(histogram[i]>maxvalue)
		maxvalue = histogram[i];
	}

	

	//maxvalue = maxvalue;
	printf("maxvalue :%d", maxvalue);

	for(int i=0; i<256; i++)
	{
		histogram[i] = histogram[i]/maxvalue*HISTO_Y;
	}
	//=================================================================
	//delete [] pVolume;
	//TODO memory leak here
	this->_hiresVol = pVolume;

	return true;

}

bool RayCaster::LoadGradientVolume(char *filename)
{
	FILE *pFile = fopen(filename,"rb");
	if (NULL == pFile) {
		return false;
	}

	int size = XMAX*YMAX*ZMAX;
	unsigned char* pVolume = new unsigned char[size*3];
	memset(pVolume,0,size*3*sizeof(unsigned char));
	size_t temp = fread(pVolume,sizeof(unsigned char), size*3,pFile);
	bool ok = (size*3 == temp);
	fclose(pFile);

	glBindTexture(GL_TEXTURE_3D,m_volumeTexture[1]);

	// set the texture parameters
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexImage3D(GL_TEXTURE_3D,0,GL_RGB8,XMAX,YMAX,ZMAX,0,GL_RGB,GL_UNSIGNED_BYTE,pVolume);

	delete [] pVolume;
	printf("loading gradient of 3D volume data ... \n");
	return true;
}
//helper function greate buffers
void RayCaster::_createProgram()
{
	vertexonlyprog.MakeProgram("vsSimple.glsl");
	//raycastprog.MakeProgram("vsSimple.glsl","raycast_new.glsl");
	raycastprog.MakeProgram("vsSimple.glsl","raycast_new - small.glsl");
	//raycastprog.MakeProgram("vsSimple.glsl","HighQualityISO.glsl");
	pass2prog.MakeProgram("screenAlignV.glsl","findCoherency.glsl");
	raycastprog2.MakeProgram("vsSimple.glsl","pass2raycasting.glsl");
	raycastprog3.MakeProgram("vsSimple.glsl","pass3raycasting.glsl");
}


void RayCaster::InitializeRayCaster()
{
	//create texture
	//texture backface_buffer
	glGenTextures(1, &m_backface);
	glBindTexture(GL_TEXTURE_2D, m_backface);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
	glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA16F_ARB, m_Width, m_Height, 0, GL_RGBA, GL_FLOAT, NULL);
	
	//texture m_raycast
	glGenTextures(1, &m_raycast);
	glBindTexture(GL_TEXTURE_2D, m_raycast);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
	glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA16F_ARB, m_Width, m_Height, 0, GL_RGBA, GL_FLOAT, NULL);

	fbo1 = new FramebufferObject();
	//fbo1->Bind();
	fbo1->AttachTexture(GL_TEXTURE_2D, m_backface,GL_COLOR_ATTACHMENT0_EXT,0,0);
    if(!fbo1->IsValid())
		std::cout<<"fbo not valid"<<std::endl;
    fbo1->Disable();

	fbo2 = new FramebufferObject();
	//fbo2->Bind();
	fbo2->AttachTexture(GL_TEXTURE_2D, m_raycast,GL_COLOR_ATTACHMENT0_EXT,0,0);
    if(!fbo2->IsValid())
		std::cout<<"fbo not valid"<<std::endl;
    fbo2->Disable();

	//================low res
	glGenTextures(1, &m_sbackface);
	glBindTexture(GL_TEXTURE_2D, m_sbackface);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
	glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA16F_ARB, m_Width*.5, m_Height*.5, 0, GL_RGBA, GL_FLOAT, NULL);
	
	//texture m_raycast
	glGenTextures(1, &m_sraycast);
	glBindTexture(GL_TEXTURE_2D, m_sraycast);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA16F_ARB, m_Width*.5, m_Height*.5, 0, GL_RGBA, GL_FLOAT, NULL);

	sfbo1 = new FramebufferObject();
	sfbo1->AttachTexture(GL_TEXTURE_2D, m_sbackface,GL_COLOR_ATTACHMENT0_EXT,0,0);
    if(! sfbo1->IsValid())
		std::cout<<"fbo not valid"<<std::endl;
    sfbo1->Disable();

	sfbo2 = new FramebufferObject();
	sfbo2->AttachTexture(GL_TEXTURE_2D, m_sraycast,GL_COLOR_ATTACHMENT0_EXT,0,0);
    if(! sfbo2->IsValid())
		std::cout<<"fbo not valid"<<std::endl;
    sfbo2->Disable();

	_createProgram();
}
void RayCaster::setTransferFunctionTexture(GLuint tex)
{
	Lut = tex;
}

// draw cube: utility function
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////OpenGL helper function////////////////////////////////////////////////////////////////////
void drawCubes(float x, float y, float z)
{
	glTranslatef(-x/2, -y/2, -z/2);

	glBegin(GL_QUADS);
	/* Back side */
	glNormal3f(0.0, 0.0, -1.0);
	glVertex3f(0.0, 0.0, 0.0);
	glVertex3f(0.0, y, 0.0);
	glVertex3f(x, y, 0.0);
	glVertex3f(x, 0.0, 0.0);

	/* Front side */
	glNormal3f(0.0, 0.0, 1.0);
	glVertex3f(0.0, 0.0, z);
	glVertex3f(x, 0.0, z);
	glVertex3f(x, y, z);
	glVertex3f(0.0, y, z);

	/* Top side */
	glNormal3f(0.0, 1.0, 0.0);
	glVertex3f(0.0, y, 0.0);
	glVertex3f(0.0, y, z);
    glVertex3f(x, y, z);
	glVertex3f(x, y, 0.0);

	/* Bottom side */
	glNormal3f(0.0, -1.0, 0.0);
	glVertex3f(0.0, 0.0, 0.0);
	glVertex3f(x, 0.0, 0.0);
	glVertex3f(x, 0.0, z);
	glVertex3f(0.0, 0.0, z);

	/* Left side */
	glNormal3f(-1.0, 0.0, 0.0);
	glVertex3f(0.0, 0.0, 0.0);
	glVertex3f(0.0, 0.0, z);
	glVertex3f(0.0, y, z);
	glVertex3f(0.0, y, 0.0);

	/* Right side */
	glNormal3f(1.0, 0.0, 0.0);
	glVertex3f(x, 0.0, 0.0);
	glVertex3f(x, y, 0.0);
	glVertex3f(x, y, z);
	glVertex3f(x, 0.0, z);
	glEnd();
	glTranslatef(x/2, y/2, z/2);
	
}
void draw_fullscreen_quad()
{
	glDisable(GL_DEPTH_TEST);
	glBegin(GL_QUADS);
   
	glTexCoord2f(0,0); 
	glVertex2f(0,0);

	glTexCoord2f(1,0); 
	glVertex2f(1,0);

	glTexCoord2f(1, 1); 
	glVertex2f(1, 1);

	glTexCoord2f(0, 1); 
	glVertex2f(0, 1);

	glEnd();
	glEnable(GL_DEPTH_TEST);

}
void reshape_ortho(int w, int h)
{
	if (h == 0) h = 1;
	glViewport(0, 0,w,h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, 1, 0, 1);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}
void setupOpenGLPerspectView(int w, int h, float *rotMat4X4, float *transVec3 )
{
	//set up views
	glViewport(0, 0, w, h); 
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, w/h, 0.0, 25.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

	//rotate
    glTranslatef( 0, 0.1, 3); 
    glTranslatef( transVec3[0], transVec3[1], transVec3[2] ); 
    glMultMatrixf(rotMat4X4);

}
void reshape_ortho(int o_w, int o_h,int w, int h )
{
	if (h == 0) 
		h = 1;
	glViewport(o_w, o_h,w,h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, 1, 0, 1);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}
void RayCaster::_drawRenderTarget(int o_x, int o_y, int x, int y, GLuint tex)
{
	//glMatrixMode(GL_MODELVIEW);
	//glPushMatrix();
	//glMatrixMode(GL_PROJECTION);
	//glPushMatrix();

	glBindTexture(GL_TEXTURE_2D,tex);
	glEnable(GL_TEXTURE_2D);

	//origin,x,y, w, h
	reshape_ortho(o_x,o_y, x, y);
	glColor4f(1.0f,1.0f,1.0f,1.0f);
	draw_fullscreen_quad();

	glDisable(GL_TEXTURE_2D);

	//glMatrixMode(GL_MODELVIEW);
	//glPopMatrix();
	//glMatrixMode(GL_PROJECTION);
	//glPopMatrix();

}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////OpenGL helper function////////////////////////////////////////////////////////////////////

void RayCaster::Render()
{
	setupOpenGLPerspectView(this->m_Width, this->m_Height, m_rotationMatrix, m_pos);

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	//==============================================Pass1
	//draw back face to texture
	fbo1->Bind();

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	glEnable(GL_CULL_FACE);

	glCullFace(GL_FRONT);

	vertexonlyprog.BeginProgram();
	drawCubes(m_x, m_y, m_z);
	vertexonlyprog.EndProgram();

	glDisable(GL_CULL_FACE);
	
	fbo1->Disable();

	//==============================================Pass2
	fbo2->Bind();
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	raycastprog.BeginProgram();

	raycastprog.setUniform1f("stepsize", stepsize);
	raycastprog.setUniform1f("isoValue", iso_value);

	raycastprog.BindTexture(GL_TEXTURE3,GL_TEXTURE_1D,Lut,"tranf");
	raycastprog.BindTexture(GL_TEXTURE2, GL_TEXTURE_3D, m_volumeTexture[0],"volumetexture");
	raycastprog.BindTexture(GL_TEXTURE1, GL_TEXTURE_3D, m_volumeTexture[1],"crackedVolume");
	raycastprog.BindTexture(GL_TEXTURE0, GL_TEXTURE_2D, m_backface,"backfacetexture");
	//raycastprog.BindTexture(GL_TEXTURE0, ...,"tranf");
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
		drawCubes(m_x, m_y, m_z); 
	glDisable(GL_CULL_FACE);

	raycastprog.EndProgram();
    fbo2->Disable();
	//===========================================
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	//_drawRenderTarget(0,0, m_Width, m_Height, m_backface);
	_drawRenderTarget(0,0, m_Width, m_Height, m_raycast);
}

void 	RayCaster::RenderDemo()
{
	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	setupOpenGLPerspectView(this->m_Width*0.5, this->m_Height*0.5, m_rotationMatrix, m_pos);
	//raycast pass=========================
	///////////////////////////////////////////////////////////////////////
	//draw back face to texture
	sfbo1->Bind();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glEnable(GL_CULL_FACE);
	glCullFace(GL_FRONT);
	vertexonlyprog.BeginProgram();
	drawCubes(m_x, m_y, m_z);
	vertexonlyprog.EndProgram();
	glDisable(GL_CULL_FACE);
	
	sfbo1->Disable();

	//====================================
	sfbo2->Bind();
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	raycastprog.BeginProgram();

	raycastprog.setUniform1f("stepsize", stepsize);
	raycastprog.setUniform1f("isoValue", iso_value);
	raycastprog.BindTexture(GL_TEXTURE3,GL_TEXTURE_1D,Lut,"tranf");
	raycastprog.BindTexture(GL_TEXTURE2, GL_TEXTURE_3D, m_volumeTexture[0],"volumetexture");
	raycastprog.BindTexture(GL_TEXTURE0, GL_TEXTURE_2D, m_sbackface,"backfacetexture");

	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
		drawCubes(m_x, m_y, m_z); 
	glDisable(GL_CULL_FACE);

	raycastprog.EndProgram();
    sfbo2->Disable();

	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	//===========================================
	setupOpenGLPerspectView(this->m_Width, this->m_Height, m_rotationMatrix, m_pos);
    fbo1->Bind();
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	
	glDisable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_FRONT);
	vertexonlyprog.BeginProgram();
	drawCubes(m_x, m_y, m_z);
	vertexonlyprog.EndProgram();
	glEnable(GL_DEPTH_TEST);

	glDisable(GL_CULL_FACE);
	fbo1->Disable();







	//check pass
	//clear stencil here!!
	glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
	glDepthMask( GL_FALSE );
	//glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );

	glEnable(GL_STENCIL_TEST);
	glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
	glStencilFunc(GL_ALWAYS, 255, 0xff);	

	pass2prog.BeginProgram();
		_drawRenderTarget(0,0, m_Width, m_Height, m_sraycast);
	pass2prog.EndProgram();

	glDisable(GL_STENCIL_TEST);
	//glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
	glDepthMask( GL_TRUE );
}


void RayCaster::ImageSpaceAdaptiveRender(float selectOutput)
{
	//low res raycasting
	//marking the pixel need refinement

	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	setupOpenGLPerspectView(this->m_Width*0.5, this->m_Height*0.5, m_rotationMatrix, m_pos);
	//raycast pass=========================
	///////////////////////////////////////////////////////////////////////
	//draw back face to texture
	sfbo1->Bind();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glEnable(GL_CULL_FACE);
	glCullFace(GL_FRONT);
	vertexonlyprog.BeginProgram();
	drawCubes(m_x, m_y, m_z);
	vertexonlyprog.EndProgram();
	glDisable(GL_CULL_FACE);
	
	sfbo1->Disable();

	//====================================
	sfbo2->Bind();
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	raycastprog.BeginProgram();

	raycastprog.setUniform1f("stepsize", stepsize);
	raycastprog.setUniform1f("isoValue", iso_value);
	raycastprog.BindTexture(GL_TEXTURE3,GL_TEXTURE_1D,Lut,"tranf");
	raycastprog.BindTexture(GL_TEXTURE2, GL_TEXTURE_3D, m_volumeTexture[0],"volumetexture");
	raycastprog.BindTexture(GL_TEXTURE0, GL_TEXTURE_2D, m_sbackface,"backfacetexture");

	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
		drawCubes(m_x, m_y, m_z); 
	glDisable(GL_CULL_FACE);

	raycastprog.EndProgram();
    sfbo2->Disable();

	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	//===========================================
	setupOpenGLPerspectView(this->m_Width, this->m_Height, m_rotationMatrix, m_pos);
    fbo1->Bind();
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	
	glDisable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_FRONT);
	vertexonlyprog.BeginProgram();
	drawCubes(m_x, m_y, m_z);
	vertexonlyprog.EndProgram();
	glEnable(GL_DEPTH_TEST);

	glDisable(GL_CULL_FACE);
	fbo1->Disable();







	//check pass
	//clear stencil here!!
	glClear(GL_STENCIL_BUFFER_BIT);
	glDepthMask( GL_FALSE );
	glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );

	glEnable(GL_STENCIL_TEST);
	glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
	glStencilFunc(GL_ALWAYS, 255, 0xff);	

	pass2prog.BeginProgram();
		_drawRenderTarget(0,0, m_Width, m_Height, m_sraycast);
	pass2prog.EndProgram();

	glDisable(GL_STENCIL_TEST);
	glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
	glDepthMask( GL_TRUE );

	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	//===========================================
	//Second render
	
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	_drawRenderTarget(0,0, m_Width, m_Height, m_sraycast);

	//////STENCIL
	glEnable(GL_STENCIL_TEST);
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
	glStencilFunc(GL_EQUAL, 255, 0xff);
	//draw back face to texture
	
	glDisable(GL_DEPTH_TEST);
	////////////////////////////////////////////////////////////////////////////////////////
	//second raycast pass
	//fbo2->Bind();
	setupOpenGLPerspectView(this->m_Width, this->m_Height, m_rotationMatrix, m_pos);
	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	raycastprog.BeginProgram();

	raycastprog.setUniform1f("stepsize", stepsize);
	raycastprog.setUniform1f("isoValue", iso_value);

	//glEnable(GL_TEXTURE_2D);
	raycastprog.BindTexture(GL_TEXTURE3,GL_TEXTURE_1D,Lut,"tranf");
	raycastprog.BindTexture(GL_TEXTURE2, GL_TEXTURE_3D, m_volumeTexture[0],"volumetexture");
	raycastprog.BindTexture(GL_TEXTURE1, GL_TEXTURE_3D, m_volumeTexture[1],"crackedVolume");
	raycastprog.BindTexture(GL_TEXTURE0, GL_TEXTURE_2D, m_backface,"backfacetexture");

	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
		drawCubes(m_x, m_y, m_z); 
	glDisable(GL_CULL_FACE);

	raycastprog.EndProgram();
	////fbo2->Disable();

	glDisable(GL_STENCIL_TEST);
	glDepthMask( GL_TRUE );
	
	//===========================================



	
	//=============================================
	

	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	//_drawRenderTarget(0,0, m_Width, m_Height, m_backface);
	//if(selectOutput>0 && selectOutput<0.2)
	//	_drawRenderTarget(0,0, m_Width, m_Height, m_sraycast);
	//else if(selectOutput>0.2 && selectOutput<1)
	//	_drawRenderTarget(0,0, m_Width, m_Height, m_sraycast);

	
}

void RayCaster::ImageSpaceAdaptiveRender2()
{
	setupOpenGLPerspectView(this->m_Width*0.5, this->m_Height*0.5, m_rotationMatrix, m_pos);
	//raycast pass=========================
	///////////////////////////////////////////////////////////////////////
	//draw back face to texture
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	sfbo1->Bind();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glEnable(GL_CULL_FACE);
	glCullFace(GL_FRONT);
	vertexonlyprog.BeginProgram();
	drawCubes(m_x, m_y, m_z);
	vertexonlyprog.EndProgram();
	glDisable(GL_CULL_FACE);
	
	sfbo1->Disable();

	//====================================
	sfbo2->Bind();
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	raycastprog.BeginProgram();

	raycastprog.setUniform1f("stepsize", stepsize);
	raycastprog.setUniform1f("isoValue", iso_value);
	raycastprog.BindTexture(GL_TEXTURE3,GL_TEXTURE_1D,Lut,"tranf");
	raycastprog.BindTexture(GL_TEXTURE2, GL_TEXTURE_3D, m_volumeTexture[0],"volumetexture");
	raycastprog.BindTexture(GL_TEXTURE0, GL_TEXTURE_2D, m_sbackface,"backfacetexture");

	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
		drawCubes(m_x, m_y, m_z); 
	glDisable(GL_CULL_FACE);

	raycastprog.EndProgram();
    sfbo2->Disable();

	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	//===========================================
	setupOpenGLPerspectView(this->m_Width, this->m_Height, m_rotationMatrix, m_pos);
    fbo1->Bind();
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	
	glDisable(GL_DEPTH_TEST);
	
	glEnable(GL_CULL_FACE);
	glCullFace(GL_FRONT);
	vertexonlyprog.BeginProgram();
	drawCubes(m_x, m_y, m_z);
	vertexonlyprog.EndProgram();

	glDisable(GL_CULL_FACE);
	fbo1->Disable();

	setupOpenGLPerspectView(this->m_Width, this->m_Height, m_rotationMatrix, m_pos);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//clear stencil here!!
	glClear(GL_STENCIL_BUFFER_BIT);
	glDepthMask( GL_FALSE );

	glEnable(GL_STENCIL_TEST);
	glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
	glStencilFunc(GL_ALWAYS, 255, 0xff);	

	raycastprog2.BeginProgram();

	raycastprog2.setUniform1f("stepsize", stepsize);
	raycastprog2.setUniform1f("isoValue", iso_value);

	//glEnable(GL_TEXTURE_2D);
	raycastprog2.BindTexture(GL_TEXTURE3,GL_TEXTURE_1D,Lut,"tranf");
	raycastprog2.BindTexture(GL_TEXTURE2, GL_TEXTURE_3D, m_volumeTexture[0],"volumetexture");
	raycastprog2.BindTexture(GL_TEXTURE1, GL_TEXTURE_2D, m_sraycast,"Image");
	raycastprog2.BindTexture(GL_TEXTURE0, GL_TEXTURE_2D, m_backface,"backfacetexture");

	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
		drawCubes(m_x, m_y, m_z); 
	glDisable(GL_CULL_FACE);

	raycastprog2.EndProgram();

	//////STENCIL
	glEnable(GL_STENCIL_TEST);
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
	glStencilFunc(GL_NOTEQUAL, 255, 0xff);
	//draw back face to texture
	_drawRenderTarget(0,0, m_Width, m_Height, m_sraycast);
	
	glDisable(GL_STENCIL_TEST);
	glDisable(GL_DEPTH_TEST);
	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	//_drawRenderTarget(0,0, m_Width, m_Height, m_backface);

}

void RayCaster::setRotation(float x, float y)
{
	m_rotationX = x;
	m_rotationY = y;

}

void RayCaster::setRotationMatrix(float* matrix)
{
	m_rotationMatrix[0] = matrix[0];
	m_rotationMatrix[1] = matrix[1];
	m_rotationMatrix[2] = matrix[2];
	m_rotationMatrix[3] = matrix[3];
	m_rotationMatrix[4] = matrix[4];
	m_rotationMatrix[5] = matrix[5];
	m_rotationMatrix[6] = matrix[6];
	m_rotationMatrix[7] = matrix[7];

	m_rotationMatrix[8] = matrix[8];
	m_rotationMatrix[9] = matrix[9];
	m_rotationMatrix[10] = matrix[10];
	m_rotationMatrix[11] = matrix[11];
	m_rotationMatrix[12] = matrix[12];
	m_rotationMatrix[13] = matrix[13];
	m_rotationMatrix[14] = matrix[14];
	m_rotationMatrix[15] = matrix[15];
}

void RayCaster::setTranslation(float* position)
{
	m_pos[0] = position[0];
	m_pos[1] = position[1];
	m_pos[2] = position[2];
}
